package com.gzc.just.play.last.war.sceneserver.gameobject.base;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.*;

/**
 * Vector3类的单元测试
 * 
 * @author AI Assistant
 * @version 1.0.0
 * @since 2025-11-25
 */
@DisplayName("三维向量类测试")
class Vector3Test {

    private Vector3 zero;
    private Vector3 unitX;
    private Vector3 unitY;
    private Vector3 unitZ;
    private Vector3 vector1;
    private Vector3 vector2;

    @BeforeEach
    void setUp() {
        zero = new Vector3(); // 默认构造
        unitX = new Vector3(1.0f, 0.0f, 0.0f);
        unitY = new Vector3(0.0f, 1.0f, 0.0f);
        unitZ = new Vector3(0.0f, 0.0f, 1.0f);
        vector1 = new Vector3(3.0f, 4.0f, 0.0f); // 长度为5的向量
        vector2 = new Vector3(5.0f, 12.0f, 0.0f); // 长度为13的向量
    }

    @Test
    @DisplayName("测试构造函数")
    void testConstructors() {
        // 默认构造函数
        assertEquals(0.0f, zero.getX(), 0.001f);
        assertEquals(0.0f, zero.getY(), 0.001f);
        assertEquals(0.0f, zero.getZ(), 0.001f);
        
        // 全参数构造函数
        Vector3 v = new Vector3(1.5f, 2.5f, 3.5f);
        assertEquals(1.5f, v.getX(), 0.001f);
        assertEquals(2.5f, v.getY(), 0.001f);
        assertEquals(3.5f, v.getZ(), 0.001f);
    }

    @Test
    @DisplayName("测试向量常量")
    void testVectorConstants() {
        // 零向量
        assertEquals(0.0f, Vector3.ZERO.getX(), 0.001f);
        assertEquals(0.0f, Vector3.ZERO.getY(), 0.001f);
        assertEquals(0.0f, Vector3.ZERO.getZ(), 0.001f);
        
        // 单位向量
        assertEquals(1.0f, Vector3.ONE.getX(), 0.001f);
        assertEquals(1.0f, Vector3.ONE.getY(), 0.001f);
        assertEquals(1.0f, Vector3.ONE.getZ(), 0.001f);
        
        // 方向向量
        assertEquals(0.0f, Vector3.UP.getX(), 0.001f);
        assertEquals(1.0f, Vector3.UP.getY(), 0.001f);
        assertEquals(0.0f, Vector3.UP.getZ(), 0.001f);
        
        assertEquals(0.0f, Vector3.DOWN.getX(), 0.001f);
        assertEquals(-1.0f, Vector3.DOWN.getY(), 0.001f);
        assertEquals(0.0f, Vector3.DOWN.getZ(), 0.001f);
        
        assertEquals(1.0f, Vector3.RIGHT.getX(), 0.001f);
        assertEquals(0.0f, Vector3.RIGHT.getY(), 0.001f);
        assertEquals(0.0f, Vector3.RIGHT.getZ(), 0.001f);
        
        assertEquals(-1.0f, Vector3.LEFT.getX(), 0.001f);
        assertEquals(0.0f, Vector3.LEFT.getY(), 0.001f);
        assertEquals(0.0f, Vector3.LEFT.getZ(), 0.001f);
        
        assertEquals(0.0f, Vector3.FORWARD.getX(), 0.001f);
        assertEquals(0.0f, Vector3.FORWARD.getY(), 0.001f);
        assertEquals(1.0f, Vector3.FORWARD.getZ(), 0.001f);
        
        assertEquals(0.0f, Vector3.BACKWARD.getX(), 0.001f);
        assertEquals(0.0f, Vector3.BACKWARD.getY(), 0.001f);
        assertEquals(-1.0f, Vector3.BACKWARD.getZ(), 0.001f);
    }

    @Test
    @DisplayName("测试向量长度")
    void testLength() {
        // 零向量长度
        assertEquals(0.0f, zero.length(), 0.001f);
        
        // 单位向量长度
        assertEquals(1.0f, unitX.length(), 0.001f);
        assertEquals(1.0f, unitY.length(), 0.001f);
        assertEquals(1.0f, unitZ.length(), 0.001f);
        
        // 3-4-5直角三角形向量长度
        assertEquals(5.0f, vector1.length(), 0.001f);
        
        // 5-12-13直角三角形向量长度
        assertEquals(13.0f, vector2.length(), 0.001f);
        
        // 立方体对角线向量
        Vector3 diagonal = new Vector3(1.0f, 1.0f, 1.0f);
        assertEquals((float)Math.sqrt(3.0), diagonal.length(), 0.001f);
    }

    @Test
    @DisplayName("测试向量规范化")
    void testNormalize() {
        // 零向量规范化
        Vector3 zeroNormalized = zero.normalize();
        assertEquals(0.0f, zeroNormalized.getX(), 0.001f);
        assertEquals(0.0f, zeroNormalized.getY(), 0.001f);
        assertEquals(0.0f, zeroNormalized.getZ(), 0.001f);
        assertEquals(0.0f, zeroNormalized.length(), 0.001f);
        
        // 非零向量规范化
        Vector3 v1Normalized = vector1.normalize();
        assertEquals(1.0f, v1Normalized.length(), 0.001f);
        assertEquals(0.6f, v1Normalized.getX(), 0.001f); // 3/5
        assertEquals(0.8f, v1Normalized.getY(), 0.001f); // 4/5
        assertEquals(0.0f, v1Normalized.getZ(), 0.001f);
        
        // 验证原始向量未被修改
        assertEquals(5.0f, vector1.length(), 0.001f);
    }

    @Test
    @DisplayName("测试点积")
    void testDotProduct() {
        // 单位向量之间的点积
        assertEquals(1.0f, unitX.dot(unitX), 0.001f); // 与自己
        assertEquals(0.0f, unitX.dot(unitY), 0.001f); // 正交
        assertEquals(0.0f, unitY.dot(unitZ), 0.001f); // 正交
        assertEquals(0.0f, unitZ.dot(unitX), 0.001f); // 正交
        
        // 不同向量之间的点积
        assertEquals(0.0f, zero.dot(vector1), 0.001f); // 零向量
        assertEquals(63.0f, vector1.dot(vector2), 0.001f); // 3*5 + 4*12 + 0*0 = 15 + 48 = 63
        
        // 与null的点积
        assertEquals(0.0f, vector1.dot(null), 0.001f);
    }

    @Test
    @DisplayName("测试叉积")
    void testCrossProduct() {
        // 单位向量之间的叉积
        Vector3 xCrossY = unitX.cross(unitY); // X × Y = Z
        assertEquals(0.0f, xCrossY.getX(), 0.001f);
        assertEquals(0.0f, xCrossY.getY(), 0.001f);
        assertEquals(1.0f, xCrossY.getZ(), 0.001f);
        
        Vector3 yCrossZ = unitY.cross(unitZ); // Y × Z = X
        assertEquals(1.0f, yCrossZ.getX(), 0.001f);
        assertEquals(0.0f, yCrossZ.getY(), 0.001f);
        assertEquals(0.0f, yCrossZ.getZ(), 0.001f);
        
        Vector3 zCrossX = unitZ.cross(unitX); // Z × X = Y
        assertEquals(0.0f, zCrossX.getX(), 0.001f);
        assertEquals(1.0f, zCrossX.getY(), 0.001f);
        assertEquals(0.0f, zCrossX.getZ(), 0.001f);
        
        // 反向叉积
        Vector3 yCrossX = unitY.cross(unitX); // Y × X = -Z
        assertEquals(0.0f, yCrossX.getX(), 0.001f);
        assertEquals(0.0f, yCrossX.getY(), 0.001f);
        assertEquals(-1.0f, yCrossX.getZ(), 0.001f);
        
        // 与null的叉积
        Vector3 nullCross = unitX.cross(null);
        assertEquals(0.0f, nullCross.getX(), 0.001f);
        assertEquals(0.0f, nullCross.getY(), 0.001f);
        assertEquals(0.0f, nullCross.getZ(), 0.001f);
    }

    @Test
    @DisplayName("测试向量加法")
    void testVectorAddition() {
        // 零向量加法
        Vector3 result = zero.add(unitX);
        assertEquals(1.0f, result.getX(), 0.001f);
        assertEquals(0.0f, result.getY(), 0.001f);
        assertEquals(0.0f, result.getZ(), 0.001f);
        
        // 常规加法
        result = vector1.add(vector2);
        assertEquals(8.0f, result.getX(), 0.001f); // 3+5
        assertEquals(16.0f, result.getY(), 0.001f); // 4+12
        assertEquals(0.0f, result.getZ(), 0.001f); // 0+0
        
        // 与null加法
        result = vector1.add(null);
        assertEquals(3.0f, result.getX(), 0.001f);
        assertEquals(4.0f, result.getY(), 0.001f);
        assertEquals(0.0f, result.getZ(), 0.001f);
    }

    @Test
    @DisplayName("测试向量减法")
    void testVectorSubtraction() {
        // 零向量减法
        Vector3 result = zero.subtract(unitX);
        assertEquals(-1.0f, result.getX(), 0.001f);
        assertEquals(0.0f, result.getY(), 0.001f);
        assertEquals(0.0f, result.getZ(), 0.001f);
        
        // 常规减法
        result = vector2.subtract(vector1);
        assertEquals(2.0f, result.getX(), 0.001f); // 5-3
        assertEquals(8.0f, result.getY(), 0.001f); // 12-4
        assertEquals(0.0f, result.getZ(), 0.001f); // 0-0
        
        // 与null减法
        result = vector1.subtract(null);
        assertEquals(3.0f, result.getX(), 0.001f);
        assertEquals(4.0f, result.getY(), 0.001f);
        assertEquals(0.0f, result.getZ(), 0.001f);
    }

    @Test
    @DisplayName("测试向量缩放")
    void testVectorScaling() {
        // 正数缩放
        Vector3 result = vector1.scale(2.0f);
        assertEquals(6.0f, result.getX(), 0.001f); // 3*2
        assertEquals(8.0f, result.getY(), 0.001f); // 4*2
        assertEquals(0.0f, result.getZ(), 0.001f); // 0*2
        
        // 零缩放
        result = vector1.scale(0.0f);
        assertEquals(0.0f, result.getX(), 0.001f);
        assertEquals(0.0f, result.getY(), 0.001f);
        assertEquals(0.0f, result.getZ(), 0.001f);
        
        // 负数缩放
        result = vector1.scale(-1.0f);
        assertEquals(-3.0f, result.getX(), 0.001f);
        assertEquals(-4.0f, result.getY(), 0.001f);
        assertEquals(0.0f, result.getZ(), 0.001f);
    }

    @Test
    @DisplayName("测试向量乘法别名")
    void testVectorMultiplyAliases() {
        // float乘法
        Vector3 result1 = vector1.multiply(2.0f);
        Vector3 result2 = vector1.scale(2.0f);
        assertEquals(result1.getX(), result2.getX(), 0.001f);
        assertEquals(result1.getY(), result2.getY(), 0.001f);
        assertEquals(result1.getZ(), result2.getZ(), 0.001f);
        
        // double乘法
        Vector3 result3 = vector1.multiply(2.0);
        assertEquals(result3.getX(), result2.getX(), 0.001f);
        assertEquals(result3.getY(), result2.getY(), 0.001f);
        assertEquals(result3.getZ(), result2.getZ(), 0.001f);
    }

    @Test
    @DisplayName("测试向量夹角")
    void testVectorAngle() {
        // 相同向量夹角为0
        assertEquals(0.0f, unitX.angleTo(unitX), 0.001f);
        
        // 正交向量夹角为90度
        assertEquals((float)(Math.PI / 2), unitX.angleTo(unitY), 0.001f);
        assertEquals((float)(Math.PI / 2), unitY.angleTo(unitZ), 0.001f);
        assertEquals((float)(Math.PI / 2), unitZ.angleTo(unitX), 0.001f);
        
        // 相反向量夹角为180度
        assertEquals((float)Math.PI, unitX.angleTo(new Vector3(-1.0f, 0.0f, 0.0f)), 0.001f);
        
        // 与零向量夹角为0
        assertEquals(0.0f, unitX.angleTo(zero), 0.001f);
        assertEquals(0.0f, zero.angleTo(unitX), 0.001f);
        
        // 与null夹角为0
        assertEquals(0.0f, unitX.angleTo(null), 0.001f);
        
        // 复杂夹角测试
        Vector3 v1 = new Vector3(1.0f, 0.0f, 0.0f);
        Vector3 v2 = new Vector3(1.0f, 1.0f, 0.0f).normalize();
        assertEquals((float)(Math.PI / 4), v1.angleTo(v2), 0.001f); // 45度
    }

    @Test
    @DisplayName("测试toString方法")
    void testToString() {
        String vString = vector1.toString();
        assertTrue(vString.contains("Vector3"));
        assertTrue(vString.contains("x=3.00"));
        assertTrue(vString.contains("y=4.00"));
        assertTrue(vString.contains("z=0.00"));
    }

    @Test
    @DisplayName("测试复杂数学场景")
    void testComplexMathScenarios() {
        // 创建一个单位立方体的所有顶点
        Vector3[] cubeVertices = {
            new Vector3(0.0f, 0.0f, 0.0f),
            new Vector3(1.0f, 0.0f, 0.0f),
            new Vector3(1.0f, 1.0f, 0.0f),
            new Vector3(0.0f, 1.0f, 0.0f),
            new Vector3(0.0f, 0.0f, 1.0f),
            new Vector3(1.0f, 0.0f, 1.0f),
            new Vector3(1.0f, 1.0f, 1.0f),
            new Vector3(0.0f, 1.0f, 1.0f)
        };
        
        // 计算立方体的对角线
        Vector3 diagonal1 = cubeVertices[6].subtract(cubeVertices[0]); // (1,1,1) - (0,0,0) = (1,1,1)
        assertEquals((float)Math.sqrt(3.0), diagonal1.length(), 0.001f);
        
        Vector3 diagonal2 = cubeVertices[5].subtract(cubeVertices[2]); // (1,0,1) - (1,1,0) = (0,-1,1)
        assertEquals((float)Math.sqrt(2.0), diagonal2.length(), 0.001f);
        
        // 验证立方体的面是正交的
        Vector3 face1 = cubeVertices[1].subtract(cubeVertices[0]); // 沿X轴
        Vector3 face2 = cubeVertices[2].subtract(cubeVertices[1]); // 沿Y轴
        Vector3 face3 = cubeVertices[4].subtract(cubeVertices[0]); // 沿Z轴
        
        assertEquals(0.0f, face1.dot(face2), 0.001f); // X垂直于Y
        assertEquals(0.0f, face2.dot(face3), 0.001f); // Y垂直于Z
        assertEquals(0.0f, face3.dot(face1), 0.001f); // Z垂直于X
        
        // 验证立方体的边长为1
        assertEquals(1.0f, face1.length(), 0.001f);
        assertEquals(1.0f, face2.length(), 0.001f);
        assertEquals(1.0f, face3.length(), 0.001f);
    }

    @Test
    @DisplayName("测试特殊情况")
    void testSpecialCases() {
        // 极小值
        Vector3 small = new Vector3(1e-20f, 1e-20f, 1e-20f);
        assertTrue(small.length() > 0.0f); // 长度应非常小但非零
        
        // 无穷值
        Vector3 infinite = new Vector3(Float.POSITIVE_INFINITY, 0.0f, 0.0f);
        assertTrue(Float.isInfinite(infinite.length())); // 长度应为无穷大
        
        // NaN值
        Vector3 nan = new Vector3(Float.NaN, 0.0f, 0.0f);
        assertTrue(Float.isNaN(nan.length())); // 长度应为NaN
        
        // 零向量点积
        Vector3 zero = Vector3.ZERO;
        assertEquals(0.0f, zero.dot(new Vector3(1, 2, 3)), 0.001f);
    }
}